<html>
<head><meta charset="utf-8"><title>Static analysis for drop of channel sender · general · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/index.html">general</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Static.20analysis.20for.20drop.20of.20channel.20sender.html">Static analysis for drop of channel sender</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="242916034"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Static%20analysis%20for%20drop%20of%20channel%20sender/near/242916034" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Static.20analysis.20for.20drop.20of.20channel.20sender.html#242916034">(Jun 16 2021 at 17:41)</a>:</h4>
<p>During training, I showed this code that uses MPSC channels and highlighted that you need to be sure to drop the "extra" <code>tx</code> to avoid having a deadlock/livelock when reading from the <code>rx</code>:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="p">(</span><span class="n">tx</span><span class="p">,</span><span class="w"> </span><span class="n">rx</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mpsc</span>::<span class="n">channel</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">t1s</span>: <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">_</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="mi">2</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="n">_</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="kd">let</span><span class="w"> </span><span class="n">tx</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tx</span><span class="p">.</span><span class="n">clone</span><span class="p">();</span><span class="w"></span>
<span class="w">            </span><span class="n">thread</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">                </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="mi">10</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">                    </span><span class="n">tx</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">i</span><span class="p">).</span><span class="n">expect</span><span class="p">(</span><span class="s">"Unable to send to thread 2"</span><span class="p">);</span><span class="w"></span>
<span class="w">                </span><span class="p">}</span><span class="w"></span>
<span class="w">            </span><span class="p">})</span><span class="w"></span>
<span class="w">        </span><span class="p">})</span><span class="w"></span>
<span class="w">        </span><span class="p">.</span><span class="n">collect</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="nb">drop</span><span class="p">(</span><span class="n">tx</span><span class="p">);</span><span class="w"></span>
</code></pre></div>
<p>Two people asked if there were any static analysis available to highlight that problem, instead of just remembering to look out for it.</p>



<a name="242948291"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Static%20analysis%20for%20drop%20of%20channel%20sender/near/242948291" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Static.20analysis.20for.20drop.20of.20channel.20sender.html#242948291">(Jun 16 2021 at 21:54)</a>:</h4>
<p>FWIW, you can also make the <code>map</code> closure be <code>move</code>: the closure then owns that last instance of <code>tx</code>, and it is dropped when that closure temporary is, that is, at the end of the statement.<br>
I don't know of a static analysis tool able to detect this, but an API change could be less susceptible to this issue: imagine if you needed to consume the initial <code>tx</code> to only then get <code>rx</code>.</p>



<a name="242949042"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Static%20analysis%20for%20drop%20of%20channel%20sender/near/242949042" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Static.20analysis.20for.20drop.20of.20channel.20sender.html#242949042">(Jun 16 2021 at 22:02)</a>:</h4>
<blockquote>
<p>make the map closure be move</p>
</blockquote>
<p>This sounds like the kind of thing I would do in my own code as it's clever and <em>much</em> more confusing than calling <code>drop</code> explicitly. </p>
<blockquote>
<p>an API change</p>
</blockquote>
<p>Which API are you thinking of? I assume not for something in <code>mpsc::*</code>.</p>



<a name="242957459"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Static%20analysis%20for%20drop%20of%20channel%20sender/near/242957459" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Static.20analysis.20for.20drop.20of.20channel.20sender.html#242957459">(Jun 16 2021 at 23:45)</a>:</h4>
<p>Let's say an API alternative; obviously not something for std, but I'll try to experiment with some designs and report back here with how they look like <span aria-label="smile" class="emoji emoji-1f642" role="img" title="smile">:smile:</span> who knows, maybe some crate could choose to feature them</p>



<a name="243010866"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Static%20analysis%20for%20drop%20of%20channel%20sender/near/243010866" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Elichai Turkel <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Static.20analysis.20for.20drop.20of.20channel.20sender.html#243010866">(Jun 17 2021 at 12:39)</a>:</h4>
<p><span class="user-mention" data-user-id="116155">@Jake Goulding</span> Is there an explanation somewhere on why there will be a deadlock here? Thanks :)</p>



<a name="243011644"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Static%20analysis%20for%20drop%20of%20channel%20sender/near/243011644" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Static.20analysis.20for.20drop.20of.20channel.20sender.html#243011644">(Jun 17 2021 at 12:47)</a>:</h4>
<p><span class="user-mention" data-user-id="249222">@Elichai Turkel</span> in the snippet of code posted, there isn’t one. The rest of the code:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">t2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">thread</span>::<span class="n">spawn</span><span class="p">(</span><span class="k">move</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="n">j</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">rx</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="fm">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="p">);</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">});</span><span class="w"></span>
<span class="w">    </span><span class="n">t1</span><span class="p">.</span><span class="n">join</span><span class="p">().</span><span class="n">expect</span><span class="p">(</span><span class="s">"Thread 1 panicked"</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="n">t2</span><span class="p">.</span><span class="n">join</span><span class="p">().</span><span class="n">expect</span><span class="p">(</span><span class="s">"Thread 2 panicked"</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="243011728"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Static%20analysis%20for%20drop%20of%20channel%20sender/near/243011728" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Static.20analysis.20for.20drop.20of.20channel.20sender.html#243011728">(Jun 17 2021 at 12:48)</a>:</h4>
<p>The rx waits for all the senders to be dropped before ending iteration</p>



<a name="243011730"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Static%20analysis%20for%20drop%20of%20channel%20sender/near/243011730" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Laurențiu <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Static.20analysis.20for.20drop.20of.20channel.20sender.html#243011730">(Jun 17 2021 at 12:48)</a>:</h4>
<p>If you write <code>for x in rx</code> or <code>rx.collect()</code>, it only finishes when the sender(s) are closed. This particular example is a bit subtle, because it's not collecting values from the channel, but <code>JoinHandle</code>s.</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>